from Tkinter import *
from tkMessageBox import *
from MVC.plstdocument import IDocument
from service.PlusterLog import PlusterLog
from service.XMLRPC import XMLRPC
from service.MainServer import MainServer
from service.pconfig import PConfig
from localEnv import *
from service.exception import *
import re
import thread
import time


class DiffView(Frame):
    def __init__(self,ctl):
        self.ctl=ctl
        self.diff_node_list=[]
        self.diff_context_list=[]
        self.same=[]
        self.index=0
        self.isOrgDisplay=False

    def exit (self):
        """ Ask adapter handle exit"""
        self.ctl.handle_exit()
        self.w.destroy()

    def show(self,master):
        self.w=Toplevel(master)
        self.w.protocol('WM_DELETE_WINDOW', self.exit)
        Frame.__init__(self,self.w)
        self.master.title("Pluster Diff Task 0.1")
        self.grid()
        self.create()


    def create(self):
        "Create Widgets for View"
        Label(self,text="Original Node:").grid(row=0,column=0)
        self.l_org_node=Entry(self)
        self.l_org_node.grid(row=0,column=1,columnspan=2)
        Label(self,text="Original File:").grid(row=1,column=0)
        self.l_org_file=Entry(self)
        self.l_org_file.grid(row=1,column=1,columnspan=2)
        Label(self,text="Compare Node Name").grid(row=2,column=0)
        self.l_cmp=Entry(self)
        self.l_cmp.grid(row=2,column=1,columnspan=2)
        self.l_stat=Label(self,text="")
        self.l_stat.grid(row=3,column=0)
        Label(self,text="Original File").grid(row=4,column=0)
        Label(self,text="Diff File").grid(row=4,column=2)
        self.org=Text(self,width=70,height=20)
        self.org.grid(row=5,column=0,sticky=E)
        self.org_scroll=Scrollbar(self,orient=VERTICAL,command=self.org.yview)
        self.org_scroll.grid(row=5,column=1,sticky=N+S)
        self.org["yscrollcommand"]=self.org_scroll.set
        self.diff=Text(self,width=70,height=20)
        self.diff_scroll=Scrollbar(self,orient=VERTICAL,command=self.diff.yview)
        self.diff_scroll.grid(row=5,column=3,sticky=N+S)
        self.diff.grid(row=5,column=2)
        self.diff["yscrollcommand"]=self.diff_scroll.set
        Button(self,text="Diff",width=10,command=self.__diff).grid(row=6,column=0)
        self.pre=Button(self,text="Previous",width=10,command=self.__prev,state=DISABLED)
        self.pre.grid(row=6,column=2)
        self.next=Button(self,text="Next",width=10,command=self.__next,state=DISABLED)
        self.next.grid(row=7,column=2)
        self.number=Label(self,text="0")
        self.number.grid(row=7,column=0)
        #self.copy=Button(self,text="Copy to node",width=10,command=self.__copy2node,default=DISABLED)
        #self.copy.grid(row=7,column=0)

    def __diff(self):
        org_node=self.l_org_node.get()
        if org_node=="":
            showerror("Input Error","Must input original node")
            return
        diff_file=self.l_org_file.get()
        if diff_file=="":
            showerror("Input Error","Must have a file name")
            return
        other=self.l_cmp.get()
        if other.find(org_node)!=-1:
            showerror('Input Error','Other node should not contain original node')
            return
        err=self.ctl.handle_diff(org_node,diff_file,other)
        if err==-1:
            showerror("File Error","Can not find file %s . Check your original file"%diff_file)


    def __next(self):
        if self.index<(len(self.diff_context_list)-1):
            self.pre['state']=NORMAL
            self.index+=1
            self.diff.delete(1.0,END)
            self.diff.insert(1.0,self.diff_context_list[self.index])
            self.number['text']=str(self.index+1)
        else:
            self.next['state']=DISABLED

    def __prev(self):
        if self.index>0:
            self.index-=1
            self.next['state']=NORMAL
            self.diff.delete(1.0,END)
            self.diff.insert(1.0,self.diff_context_list[self.index])
            self.number['text']=str(self.index+1)
        else:
            self.pre['state']=DISABLED



    def __copy2node(self):
        pass


    def Update(self,doc):
        if self.isOrgDisplay:
            pass
        else:
            self.org.insert(END,doc.org_file_context)
            self.isOrgDisplay=True
        self.diff_node_list=doc.diff_node_list
        self.diff_context_list=doc.diff_context_list
        self.same=doc.same_node_list
        if len(self.diff_node_list)==1:
            self.next['state']=NORMAL
            #self.copy['state']=NORMAL
            self.diff.insert(END,self.diff_context_list[0])
        if len(self.diff_node_list)==2:
            self.pre['state']=NORMAL
        self.l_stat['text']="Finish %d nodes, %d same %d different"%\
                             (len(self.diff_node_list)+len(self.same),
                              len(self.same),len(self.diff_node_list))



class DiffAdapter:
    def __init__(self,doc):
        self.doc=doc

    def handle_diff(self,name,f,other):
        try:
            node_doc=MainServer.obj.get_node(name)
        except:
            return name
        node_list=re.findall(r"\w+",other)
        node_doc_list=[]
        if node_list:
            for i in node_list:
                try:
                    temp=MainServer.obj.get_node(i)
                except:
                    return i
                node_doc_list.append(temp)
        self.doc.config(node_doc,f,node_doc_list)
        return self.doc.run()

    def handle_exit (self):
        """ handle diff exit"""
        self.doc.exit()


class DiffTask(IDocument,PlusterLog):
    def __init__(self):
        IDocument.__init__(self)
        PlusterLog.__init__(self)
        self.org_file_context=''# put original file text
        self.diff_file_context=''# put diff text
        self.diff_node_list=[]
        self.diff_context_list=[]
        self.same_node_list=[]
        self.mutex =thread.allocate_lock()
        self.port=None

    def exit (self):
        """ Return port"""
        if self.port:
            XMLRPC.rpcDaemon.ReleasePort(self.port)
            self.log.debug('Release Port %d'%self.port)


    def config(self,org_node,org_file,other_node):
        self.org_node=org_node
        self.file_path=org_file
        self.other_list=other_node

    def run(self):
        self.port=XMLRPC.rpcDaemon.RequestPort(self)
        #print "Diff get port: ",self.port
        self.log.info("Running Task: Diff")
        net=PConfig.attribute.ms_net
        self.ip=get_ip(net)
        err=self.org_node.load_remote_task('Rfile',\
                                               self.ip,\
                                               self.port,\
                                               self.file_path)
        if err==-1:
            return err

        time.sleep(1)
        if not self.org_file_context:
            time.sleep(2)
        if not self.org_file_context:
            self.log.error("Time out. Can not get original file!")
            return


        for node in self.other_list:
            node.load_remote_task('Rdiff',\
                                  self.ip,self.port,\
                                  self.file_path,\
                                  self.org_file_context)



    def _read_file(self,ip,port,path):
        """read remote file

        return string of file"""


    def _set_orig_node(self,node):
        """load task of the node who store original file

        return None"""
        pass

    def _poll_node(self,orig_node,path,*node):
        """poll other node to read file from orig_node

        return a list of nodes that have different file"""
        pass

    def report_diff(self,node_name,diff_string):
        """report different by remote node

        return 0
        """
        self.mutex.acquire()
        self.diff_node_list.append(node_name)
        self.diff_context_list.append(diff_string)
        self.mutex.release()
        self.Flush()
        return 0

    def report_same(self,node_name):
        self.same_node_list.append(node_name)
        self.Flush()
        return 0

    def recv(self,str):
        "bind method to receive file"
        self.org_file_context=str
        self.Flush()
        return 0



